package com.rgs.base.core.file.storage;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Strings;
import com.rgs.base.core.exception.BaseException;
import com.rgs.base.core.exception.CoreException;
import com.rgs.base.core.system.WebResponseState;
import com.rgs.base.core.util.FileStaticClass;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.InputStream;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.util.Objects;

import static com.rgs.base.core.file.storage.FilePathUtil.createPath;

/**
 * @author Ren Gaoshuai
 * @date 2021/12/13 14:08
 */
@Service
@ConditionalOnProperty(prefix = "rgs.storage", name = "type", havingValue = "file")
public class FileStorageServiceImpl implements FileStorageService {
    @Value("${rgs.file.config.path}")
    private String filePath;
    @Value("${rgs.file.config.url}")
    private String fileUrl;

    private static File ROOT_FILE;
    private final static int MAX_PATH_NUMBER = 255;

    @PostConstruct
    public void init() {
        this.initPath();
        ROOT_FILE = new File(filePath);
    }

    @Override
    public void initPath() {
        for (int i = 0; i <= MAX_PATH_NUMBER; i++) {
            for (int j = 0; j <= MAX_PATH_NUMBER; j++) {
                String path = filePath.concat(createPath(i, j));
                if (!FileUtil.exist(path)) {
                    FileUtil.mkdir(path);
                }
            }
        }
    }

    @Override
    public void clear() {
        FileUtil.clean(ROOT_FILE);
    }

    @Override
    public void saveForInputStream(InputStream inputStream, String fileName) {
        File file = this.buildFile(fileName);
        FileUtil.writeFromStream(inputStream, file);
    }

    @Override
    public void delete(String fileName) {
        File file = this.buildFile(fileName);
        FileUtil.del(file);
    }

    @Override
    public void saveForByte(byte[] fileBytes, String fileName) {
        File file = this.buildFile(fileName);
        FileUtil.writeBytes(fileBytes, file);
    }

    @Override
    public boolean exist(String fileName) {
        return this.buildFile(fileName).exists();
    }

    @Override
    public String generateFileName(String suffix) {
        return IdUtil.fastSimpleUUID().concat(".").concat(suffix);
    }

    @Override
    public String copy(String fileName) {
        String prefix = FileUtil.getPrefix(fileName);
        String destFileName = this.generateFileName(prefix);
        File destFile = this.buildFile(destFileName);
        File srcFile = this.buildFile(fileName);
        FileUtil.copyFile(srcFile, destFile, StandardCopyOption.REPLACE_EXISTING);
        return destFileName;
    }

    @Override
    public String fileUrl(String fileId) {
        return fileUrl(fileId, null);
    }

    @Override
    public String fileUrl(String fileId, String aliasName) {
        return fileUrl(fileId, aliasName, null);
    }

    @Override
    public String fileUrl(String fileId, String aliasName, LocalDate localDate) {
        if (Strings.isNullOrEmpty(fileId)) {
            return "";
        }
        String[] split = fileId.split("\\.");
        String url = createPath(fileId).concat(split[0]).concat(".").concat(split[1]);
        url = StrUtil.replace(url, "\\", "/");
        url = fileUrl.concat(url);
        if (!Strings.isNullOrEmpty(url) && !Strings.isNullOrEmpty(aliasName)) {
            url = url.concat(FileStaticClass.NGINX_NAME)
                    .concat(aliasName)
                    .concat(Objects.isNull(localDate) ? "" :
                            LocalDateTimeUtil.formatNormal(localDate))
                    .concat(".").concat(split[1]);

        }
        return url;
    }

    @Override
    public byte[] obtainFileForBytes(String fileId) {
        File file = this.buildFile(fileId);
        if (!file.exists()) {
            throw new CoreException("文件不存在");
        }
        return FileUtil.readBytes(file);
    }

    @Override
    public String obtainFileForBase64(String fileId) {
        File file = this.buildFile(fileId);
        return Base64.encode(file);
    }

    private File buildFile(String id) {
        String path = createPath(id);
        return new File(filePath.concat(path).concat(id));
    }

    @Override
    public InputStream obtainFileForInputStream(String fileName) {
        File file = this.buildFile(fileName);
        if (!file.exists()) {
            throw new BaseException("文件模块", WebResponseState.NO_FILE);
        }
        return FileUtil.getInputStream(file);
    }
}
